package com.sxkiler.demo.rpc.client;

import com.sxkiler.demo.rpc.model.RpcReference;
import com.sxkiler.demo.rpc.pojo.Book;
import com.sxkiler.demo.rpc.pojo.MessageContext;
import com.sxkiler.demo.rpc.pojo.Request;
import com.sxkiler.demo.rpc.pojo.User;
import com.sxkiler.demo.rpc.service.BookService;
import com.sxkiler.demo.rpc.service.UserService;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class InvokeService {

    @RpcReference(referenceName = "BookServiceImpl")//自定义注解，服务依赖。指定名称跟服务端保持一致
    private BookService bookService;

    @RpcReference(referenceName = "UserServiceImpl")//自定义注解，服务依赖。指定名称跟服务端保持一致
    private UserService userService;


    private ExecutorService executorService = Executors.newFixedThreadPool(8);//创建一个线程池

    public InvokeService(Class<?> className, NettyClientHandler nettyClientHandler) {
        this.bookService = (BookService) getBean(className, nettyClientHandler);//初始化时会调用一个getBean方法。该方法会创建被调用服务的代理对象
    }

    public Object getBean(Class<?> className, NettyClientHandler nettyClientHandler) {
        //通过proxy创建被调用者className的代理对象。
        Object proxyInstance = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{className}, ((proxy, method, args) -> {
            //并重写调用逻辑。当对象被代理后，你调用原对象方法，会拦截进入到该逻辑处理
            //封装请求体数据
            Request request = new Request();
            request.setClassName(className.getSimpleName());
            request.setMethodName(method.getName());
            request.setParameterType(method.getParameterTypes());
            request.setParameterValue(args);
            Field userServiceField = InvokeService.class.getDeclaredField("bookService");
            //获取bookService字段的@RpcReference注解的name属性传给服务端，服务端通过这个bean的name属性去bean容器查找对象
            request.setServiceNameByAnnotated(userServiceField.getAnnotation(RpcReference.class).referenceName());
            MessageContext messageContext = new MessageContext(String.valueOf(new Random().nextInt(9999)), true, request);
            //把消息体放入到nettyClientHandler中，以供nettyClientHandler去发送数据
            nettyClientHandler.setMessageContext(messageContext);
            //把具体远程调用处理传给线程池去异步处理。
            Object o = executorService.submit(nettyClientHandler).get();
            return o;
        }));
        return proxyInstance;
    }

    public User getUser() {
        return userService.getUser(1);
    }

    public User updateUser() {
        return userService.updateUser(getUser());
    }

    public int delUser() {
        return userService.deleteUser(1);
    }

    public int insertUser() {
        return userService.insertUser(getUser());
    }

    Book getBook(Integer id) {
        return bookService.getBook(id);
    }

    Book updateBook(Book book) {
        return bookService.updateBook(book);
    }

    Integer delBook(Integer id) {
        return bookService.delBook(id);
    }

    Integer insertBook(Book book) {
        return bookService.insertBook(book);
    }
}
